/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * BuscarImagenInicio.java
 *
 * Created on 26-feb-2012, 11:34:30
 */

package proy1sistdistribuidos.interfaz;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.SecretKey;
import javax.print.attribute.HashAttributeSet;
import javax.swing.JOptionPane;
import proy1sistdistribuidos.control.advertisements.AdvertisementContenidoFisicoImpl;
import proy1sistdistribuidos.control.advertisements.AdvertisementImagenImpl;
import proy1sistdistribuidos.modelo.AdministradorJXTA;
import proy1sistdistribuidos.modelo.ControladorEstado;
import proy1sistdistribuidos.modelo.ControladorExclusion;
import proy1sistdistribuidos.modelo.ControladorProySistDistribuidos;
import proy1sistdistribuidos.modelo.EstadoGeneral;
import proy1sistdistribuidos.modelo.NodoRemoto;
import proy1sistdistribuidos.modelo.TiposMime;
import proy1sistdistribuidos.modelo.seguridad.EncriptadorDesencriptador;
import proy1sistdistribuidos.modelo.seguridad.EncriptadorDesencriptadorAES;
import proy1sistdistribuidos.modelo.seguridad.EncriptadorDesencriptadorDES;
import proy1sistdistribuidos.modelo.seguridad.GeneradorCodigosHash;
import proy1sistdistribuidos.modelo.seguridad.GeneradorCodigosHashSHA512;
import proy1sistdistribuidos.modelo.seguridad.InformacionSocketDF;
import proy1sistdistribuidos.modelo.seguridad.IntercambiadorLlaves;
import proy1sistdistribuidos.modelo.seguridad.IntercambiadorLlavesDF;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 *
 * @author Juan Felipe Garcia, Carlos Diaz Maya
 */
public class BuscarImagenInicio extends javax.swing.JFrame implements Observer {
    private String etiqueta;
    private File archivoSeleccionado;
    private ControladorProySistDistribuidos controlador;
    private PTableModel modeloTabla;
    private String etiquetaSeleccionada;
    private HashMap<String, AdvertisementImagenImpl> results = new HashMap<String, AdvertisementImagenImpl>();

    /** Creates new form BuscarImagenInicio */
    public BuscarImagenInicio() {
        initComponents();
    }

    public BuscarImagenInicio(ControladorProySistDistribuidos cont){
        this.controlador = cont;
        inicializarColumnasTabla();
        initComponents();
    }


    public void inicializarColumnasTabla() {
        ArrayList columnas = new ArrayList();
        columnas.add("Etiqueta");
        columnas.add("Fecha de creación");
        columnas.add("Nombres de personas");
        this.modeloTabla = new PTableModel(columnas);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLabel1 = new javax.swing.JLabel();
        jtextimagen = new javax.swing.JTextField();
        jButton1 = new javax.swing.JButton();
        jScrollPane1 = new javax.swing.JScrollPane();
        jTable1 = new javax.swing.JTable();
        jButton2 = new javax.swing.JButton();
        jButton3 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setName("Form"); // NOI18N

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(proy1sistdistribuidos.interfaz.Principal.class).getContext().getResourceMap(BuscarImagenInicio.class);
        jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N
        jLabel1.setName("jLabel1"); // NOI18N

        jtextimagen.setText(resourceMap.getString("jtextimagen.text")); // NOI18N
        jtextimagen.setName("jtextimagen"); // NOI18N

        jButton1.setText(resourceMap.getString("jButton1.text")); // NOI18N
        jButton1.setName("jButton1"); // NOI18N
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        jTable1.setModel(modeloTabla);
        jTable1.setName("jTable1"); // NOI18N
        jScrollPane1.setViewportView(jTable1);

        jButton2.setText(resourceMap.getString("jButton2.text")); // NOI18N
        jButton2.setName("jButton2"); // NOI18N
        jButton2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton2ActionPerformed(evt);
            }
        });

        jButton3.setText(resourceMap.getString("jButton3.text")); // NOI18N
        jButton3.setName("jButton3"); // NOI18N
        jButton3.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton3ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(layout.createSequentialGroup()
                        .addGap(21, 21, 21)
                        .addComponent(jLabel1)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jtextimagen, javax.swing.GroupLayout.PREFERRED_SIZE, 159, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addGap(110, 110, 110)
                        .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 201, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(layout.createSequentialGroup()
                        .addContainerGap()
                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE)))
                .addContainerGap())
            .addGroup(layout.createSequentialGroup()
                .addGap(31, 31, 31)
                .addComponent(jButton2, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 85, Short.MAX_VALUE)
                .addComponent(jButton3, javax.swing.GroupLayout.PREFERRED_SIZE, 115, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(52, 52, 52))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(19, 19, 19)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(jtextimagen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButton2)
                    .addComponent(jButton3))
                .addContainerGap(19, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
        //solicitud de los permisos
        this.controlador.solicitarPermisoNodos();
    }//GEN-LAST:event_jButton1ActionPerformed

    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton3ActionPerformed
         ControladorEstado.obtenerInstancia().setEstadoLocal(ControladorEstado.ESTADOABIERTO);
         this.controlador.removeObserver(this);
         this.dispose();
    }//GEN-LAST:event_jButton3ActionPerformed

    private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton2ActionPerformed
        int filaSel = this.jTable1.getSelectedRow();
        ArrayList fila = this.modeloTabla.getRowAt(filaSel);
        String idEtiqueta = (String) fila.get(0);
        try{
            String idContenidoFisico = controlador.calcularHashEtiqueta(idEtiqueta);
            this.etiquetaSeleccionada = idEtiqueta;
            controlador.obtenerInformacionImagen(idContenidoFisico);

        } catch(Exception f){
            f.printStackTrace();
        }


    }//GEN-LAST:event_jButton2ActionPerformed

    /**
    * @param args the command line arguments
    */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new BuscarImagenInicio().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton1;
    private javax.swing.JButton jButton2;
    private javax.swing.JButton jButton3;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTable jTable1;
    private javax.swing.JTextField jtextimagen;
    // End of variables declaration//GEN-END:variables

    public void update(Observable o, Object arg) {
       
      if(arg instanceof List){
          List<AdvertisementImagenImpl> lista = null;
          try {
                if (arg != null) {
                    lista = null;
                    List listprb = (List) arg;
                    Iterator elIt = listprb.iterator();
                    while (elIt.hasNext()) {
                        Object obu = elIt.next();
                        if (obu instanceof NodoRemoto) {
                            lista = null;
                            break;
                        } else if (obu instanceof AdvertisementImagenImpl) {
                            lista = (List<AdvertisementImagenImpl>) listprb;
                            break;
                        }
                    }
                }
            } catch (Exception f) {
                lista = null;
            }
          if(lista != null){
              this.modeloTabla.clear();
              this.results.clear();
              for(AdvertisementImagenImpl img:lista){
                   ArrayList lista2 = new ArrayList();
                   lista2.add(img.getEtiqueta());
                   lista2.add(img.getFechaCreacion());
                   List<String[]> pers = img.getListaPersonas();
                   if(pers==null){
                       lista2.add("");
                   } else {
                       String cadena = "";

                        boolean primero = true;
                        for(String[] per:pers){
                            if(primero){
                                primero = false;
                            } else {
                                cadena += ", ";
                            }
                            cadena += per[0] + " " + per[1];
                        }
                        lista2.add(cadena);
                  }
                  this.modeloTabla.addRow(lista2);
                  this.results.put(img.getEtiqueta(), img);
              }
          } else {
          }

      }
    else if(arg instanceof AdvertisementContenidoFisicoImpl) {
        AdvertisementContenidoFisicoImpl cont = (AdvertisementContenidoFisicoImpl) arg;
        String nomarch = this.etiquetaSeleccionada;

        if(nomarch!=null){
             try {
                AdvertisementImagenImpl infoImg = this.results.get(nomarch);

                //Se obtiene la direccion ip del nodo actual
                String miIp = InetAddress.getLocalHost().getHostAddress().toString();


                //Realizar acuerdo Diffie Hellman
                IntercambiadorLlaves interc = IntercambiadorLlavesDF.obtenerSolitario();
                String idSesion = miIp+"_"+infoImg.getDireccionIp();

                //En el id de la sesion va la ip del equipo destino con el que debe
                //conectarse
                interc.enviarIntercambioLlaves(idSesion);

                SecretKey llaveIntercambio = interc.obtenerLlaveEncripcionDesencripcionAcordada(idSesion);
                EncriptadorDesencriptador encdescIntercambio = EncriptadorDesencriptadorDES.obtenerSolitario();

                // Obtener llave AES:
                //1-Abrir socket a nodo que contiene la llave
                String resultado = null;
                resultado = this.enviarComandoSolicitarLlaveDesencripcion(idSesion);

                //2-Desencripta el mensaje recibido a traves del socket
                String llaveAESXml = encdescIntercambio.desencriptarMensaje(resultado, llaveIntercambio);
                //3-Serializa la llave
                XStream elStream = new XStream(new DomDriver());
                elStream.alias("FriendlyInfo", SecretKey.class);
                //4-Obtiene la llave en Objeto SecretKey
                SecretKey llaveAESDesencripcion = (SecretKey) elStream.fromXML(llaveAESXml);

                //Se crea instancia del descifrador AES
                EncriptadorDesencriptador encdescAES = EncriptadorDesencriptadorAES.obtenerSolitario();


                String extension = "";
                String mime = encdescAES.desencriptarMensaje(cont.getMimeTypeArchivoFisico(),llaveAESDesencripcion);
                if(mime.equals(TiposMime.MIMETYPEPNG)){
                    extension = ".png";
                } else if(mime.equals(TiposMime.MIMETYPEGIF)){
                    extension = ".gif";
                } else if(mime.equals(TiposMime.MIMETYPEJPG)){
                    extension = ".jpg";
                }

                String nombreArchivoImagen = ControladorProySistDistribuidos.rutaCarpetaDescarga + nomarch + extension;

                File archivo = new File(nombreArchivoImagen);
                if(!archivo.exists()){
                    archivo.createNewFile();
                }

                //Se escribe la imagen
                FileOutputStream fos = new FileOutputStream(archivo);

                String contenidoArchivoB64 = encdescAES.desencriptarMensaje(cont.getContenidoBase64(), llaveAESDesencripcion);
                BASE64Decoder dec = new BASE64Decoder();
                byte[] imagen = dec.decodeBuffer(contenidoArchivoB64);

                //Se encripta el binario de la imagen con la llave AES del equipo local
                EncriptadorDesencriptador encdesclocal = EncriptadorDesencriptadorAES.obtenerSolitario();
                SecretKey llaveLocal = AdministradorJXTA.obtenerLlaveAES();
                if(llaveLocal==null){
                    //-- En caso de no tener una llave, se crea y se guarda en disco
                     llaveLocal = encdesclocal.construirLlave();
                    AdministradorJXTA.guardarLlaveAES(llaveLocal);
                }
                String imagenEncriptadaAESLocal = encdesclocal.encriptarMensaje(contenidoArchivoB64, llaveLocal);

                //Se verifica el hash de la imagen para verificar su integridad
                GeneradorCodigosHash hash = GeneradorCodigosHashSHA512.obtenerSolitario();
                String hashRecibido = hash.generarCodigoHash(imagen);

                if(hashRecibido.equals(infoImg.getHashArchivo())) {
                    fos.write(imagenEncriptadaAESLocal.getBytes());
                    fos.close();
                 } else {
                    fos.close();
                    throw new Exception("El contenido del archivo descargado fue cambiado durante la descarga. Por favor, vuelva a descargar el archivo.");
                 }


                File archivoPersonas = new File(ControladorProySistDistribuidos.rutaCarpetaDescarga + nomarch + ".ips");
                if(!archivoPersonas.exists()){
                    archivoPersonas.createNewFile();
                }

                PrintWriter wrt1 = new PrintWriter(archivoPersonas);

                List<String[]> pers = infoImg.getListaPersonas();
                if(pers==null){
                    wrt1.close();
                } else {
                    for(String[] per:pers){
                        wrt1.println(encdesclocal.encriptarMensaje(per[0]+";"+per[1],llaveLocal));
                    }
                    wrt1.close();
                 }

                File archivoDetalles = new File(ControladorProySistDistribuidos.rutaCarpetaDescarga + nomarch + ".iim");
                if(!archivoDetalles.exists()){
                    archivoDetalles.createNewFile();
                }
                
                PrintWriter wrt2 = new PrintWriter(archivoDetalles);
                wrt2.println(encdesclocal.encriptarMensaje(infoImg.getEtiqueta(), llaveLocal));
                wrt2.println(encdesclocal.encriptarMensaje(infoImg.getFechaCreacion(), llaveLocal));
                wrt2.println(encdesclocal.encriptarMensaje(AdvertisementImagenImpl.formato.format(new Date()), llaveLocal));

                wrt2.close();

                JOptionPane.showMessageDialog(null,"Archivo descargado exitosamente.", "Exito", JOptionPane.INFORMATION_MESSAGE);

            } catch (IOException ex) {
                    Logger.getLogger(BuscarImagenInicio.class.getName()).log(Level.SEVERE, null, ex);
            } catch (Exception ex) {
                    Logger.getLogger(BuscarImagenInicio.class.getName()).log(Level.SEVERE, null, ex);
            }
          }
        } else if (arg instanceof String) {
            if (arg != null && ((String) arg).equalsIgnoreCase("tengoPermiso")) {
                
                try {
                    
                    //logica de la busqueda
                    this.etiqueta = jtextimagen.getText();
                    this.controlador.buscarArchivosPorEtiqueta(etiqueta);

                    /*EstadoGeneral estadoGeneral = ControladorEstado.obtenerInstancia().getEstadoLocalDescarga();
                    estadoGeneral.setNombreEstado(estadoGeneral.INVOCAR_CONSULTA);
                    estadoGeneral.setMensaje("");
                    ControladorEstado.obtenerInstancia().actualizarEstadoGeneralInicial(estadoGeneral);*/

                }catch (Exception ex) {
                    Logger.getLogger(BuscarImagenInicio.class.getName()).log(Level.SEVERE, null, ex);

                } 
            } else {
                JOptionPane.showMessageDialog(this, "No tiene autorización para realizar la operación");
            }
        }
    }

    private String enviarComandoSolicitarLlaveDesencripcion(String idSesion) throws Exception {
        String ipDestino = idSesion.split("_")[1];
        
        Socket elSockete = new Socket(ipDestino, ControladorExclusion.puertoSocketes);

         // Fase 2 acuerdo: Se envia el comando con la cadena encriptada con algoritmo blowfish
         String comando = "SolicLlave_"+idSesion;
         PrintWriter pregunta = new PrintWriter(elSockete.getOutputStream(), true);
         BufferedReader respuesta = new BufferedReader(new InputStreamReader(elSockete.getInputStream()));

         //Se envia el comando al nodo
         pregunta.println(comando);

         //Se recibe la respuesta del nodo
         String respNodo = respuesta.readLine();


         if (respNodo != null && !respNodo.equals("")) {
            //Se recibe los datos del acuerdo codificados en blowfish
            elSockete.close();
            return respNodo;
        } else {
             elSockete.close();
             return null;
        }
    }

}
